package com.distributed.logicserver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.mina.core.session.IoSession;

import com.distributed.common.BaseEntry;
import com.distributed.common.User;
import com.distributed.common.message.LeaveNotifyMessage;

public class UserSet {
	private Map<String, BaseEntry<IoSession, User>> users = new HashMap<String, BaseEntry<IoSession, User>>();
	private Map<IoSession, User> ioSessions = new HashMap<IoSession, User>();
	private Map<String, CopyOnWriteArrayList<User>> tables = new HashMap<String, CopyOnWriteArrayList<User>>();

	public UserSet() {
	};

	public synchronized void addUser(String userName, IoSession ioSession, User user) {
		users.put(userName, new BaseEntry<IoSession, User>(ioSession, user));
		ioSessions.put(ioSession, user);
	}

	public synchronized CopyOnWriteArrayList<User> getTableUsers(String tablename) {
		return getTableUs(tablename);
	}
	
	private CopyOnWriteArrayList<User> getTableUs(String tablename) {
		if (tablename == null || "".equals(tablename)) {
			return null;
		}
		return tables.get(tablename);		
	}
	
	private List<IoSession> getTableSs(String tablename) {
		CopyOnWriteArrayList<User> uss = getTableUs(tablename);
		if (uss == null) {
			return null;
		}
		List<IoSession> sessions = new ArrayList<IoSession>();
		
		for(int i = 0; i < uss.size(); i++) {
			sessions.add(users.get(uss.get(i).getUserName()).getKey());
		}
		
		return sessions;
	}
	
	public synchronized boolean createTable(String tablename, User user) {
		if (tablename == null || "".equals(tablename) || user == null) {
			return false;
		}
		if (tables.containsKey(tablename) == true) {
			return false;
		}
		CopyOnWriteArrayList<User> gamers = new CopyOnWriteArrayList<User>();
		gamers.add(user);
		tables.put(tablename, gamers);
		return true;
	}
	
	public synchronized boolean addTable(String tablename, User user) {
		if (tablename == null || "".equals(tablename) || user == null) {
			return false;
		}
		if (tables.containsKey(tablename) == false) {
			return false;
		}
		List<User> gamers = tables.get(tablename);
		gamers.add(user);
		return true;
	}
	
	public synchronized void removeFromTable(String tablename) {
		removeFromTb(tablename);
	}
	
	private void removeFromTb(String tablename) {
		if (tablename == null || "".equals(tablename)) {
			return;
		}
		List<User> users = tables.get(tablename);
		if (users == null || users.size() == 0) {
			return;
		}
 		for(int i = 0; i < users.size(); i++) {
			if (tablename.equals(users.get(i).getUserName())) {
				users.remove(i);
				break;
			}
		}
		
		if (users.size() == 0) {
			tables.remove(tablename);
		}
	}
	
	public synchronized BaseEntry<IoSession, User> getByUserName(String userName) {
		return getByUserNm(userName);
	}

	private BaseEntry<IoSession, User> getByUserNm(String userName) {
		return users.get(userName);
	}
	
	public synchronized User getBySession(IoSession ioSession) {
		return getBySs(ioSession);
	}
	
	private User getBySs(IoSession ioSession) {
		return ioSessions.get(ioSession);
	}
	
	public synchronized void remove(String userName) {
		BaseEntry<IoSession, User> entry = getByUserNm(userName);
		users.remove(userName);
		ioSessions.remove(entry.getKey());
		removeFromTb(entry.getValue().getTableName());
		
		List<IoSession> sessions = getTableSs(entry.getValue().getTableName());
		sessions.remove(entry.getKey());
		String message = new LeaveNotifyMessage(entry.getValue().getUserName()).toString();
		broadcast(sessions, message);
	}
	
	public synchronized void remove(IoSession ioSession) {
		User user = getBySs(ioSession);
		String userName = user.getUserName();
		BaseEntry<IoSession, User> entry = getByUserNm(userName);
		users.remove(userName);
		ioSessions.remove(entry.getKey());
		removeFromTb(entry.getValue().getTableName());
		
		List<IoSession> sessions = getTableSs(entry.getValue().getTableName());
		sessions.remove(entry.getKey());
		String message = new LeaveNotifyMessage(entry.getValue().getUserName()).toString();
		broadcast(sessions, message);
	}
	
	private void broadcast(List<IoSession> sessions, String message) {
		if (sessions == null) {
			return;
		}
		for (IoSession session : sessions) {
			if (session.isConnected()) {
				session.write(message);
			}
		}
	}
	
	public synchronized void broadcast(String tablename, String message) {
		List<IoSession> sessions = getTableSs(tablename);
		broadcast(sessions, message);
	}
}
